﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ComTools
{
    public partial class frmLG220L2 : Form
    {
        public frmLG220L2()
        {
            InitializeComponent();
        }

        private string IP
        {
            get
            {
                return mtbIPAddr.Text.Replace(" ", "").Trim();
            }
        }

        private int Port
        {
            get
            {
                return Convert.ToInt32(nudPort.Value);
            }
        }

        #region Output

        Action<string> OutputHandler = null;

        void Output(string msg)
        {
            if (OutputHandler == null)
            {
                OutputHandler = new Action<string>((txt) =>
                {
                    richTextBox1.AppendText(txt);
                    richTextBox1.SelectionStart = richTextBox1.Text.Length;
                    richTextBox1.ScrollToCaret();
                });
            }

            richTextBox1.Invoke(OutputHandler, msg);
        }

        void OutputLine(string msg)
        {
            Output(msg + Environment.NewLine);
        }

        #endregion

        private void frmSocketClient2_Load(object sender, EventArgs e)
        {
            //
            DataTable dt = InitCommandList();
            cbxCommandList.DataSource = dt;
            cbxCommandList.DisplayMember = "name";
            cbxCommandList.ValueMember = "command";
        }

        Socket socketReceive = null;

        private void btnListen_Click(object sender, EventArgs e)
        {
            if (socketReceive == null)
            {
                socketReceive = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            }

            IPAddress ip = IPAddress.Parse(IP);
            try
            {
                socketReceive.Bind(new IPEndPoint(ip, Port));
                socketReceive.Listen(5);
                socketReceive.BeginAccept(AcceptCallback, socketReceive);
                HasStopped = false;
                OutputLine("监听中...");
            }
            catch (Exception exc)
            {
                OutputLine(exc.Message);
            }
        }

        void AcceptCallback(IAsyncResult asyncResult)
        {
            if (HasStopped) { return; }
            try
            {
                OutputLine("收到呼入的连接");
                Socket socketTemp = asyncResult.AsyncState as Socket;
                Socket socketAccept = socketTemp.EndAccept(asyncResult);
                listSockets.Add(socketAccept);

                Thread thread = new Thread(new ParameterizedThreadStart(KeepReceiving));
                thread.Start(socketAccept);
                //
                if (!HasStopped)
                {
                    socketTemp.BeginAccept(AcceptCallback, socketTemp);
                }
            }
            catch (Exception exc)
            {
                OutputLine(exc.Message);
            }
        }

        private void KeepReceiving(object obj)
        {
            if (HasStopped) { return; }
            OutputLine("接收侦测中。。。");
            Socket socket = obj as Socket;
            //
            byte[] data = new byte[2048];
            socket.BeginReceive(data, 0, data.Length, SocketFlags.None, new AsyncCallback((iasr) =>
            {
                int len = socket.EndReceive(iasr);
                //
                byte[] recBytes = new byte[len];
                Array.Copy(data, recBytes, len);
                string txt = BitConverter.ToString(recBytes);
                OutputLine("has receive " + len.ToString() + " 个字节 : " + txt);
                //
                if (IsCloseCommand(recBytes))
                {
                    HasStopped = true;
                    return;
                }
                //
                KeepReceiving(socket);
            }), socket);
        }

        private volatile bool HasStopped = true;
        private bool IsCloseCommand(byte[] data)
        {
            bool result = true;
            int len = data.Length;
            if (len == closeCommand.Length)
            {
                for (int x = 0; x < len; x++)
                {
                    if (data[x] != closeCommand[x])
                    {
                        result = false;
                        break;
                    }
                }
            }
            else
            {
                result = false;
            }
            return result;
        }

        List<Socket> listSockets = new List<Socket>();

        private void btnServerSend_Click(object sender, EventArgs e)
        {
            cbxCommandList_SelectedIndexChanged(cbxCommandList, null);
            //
            if (HasStopped) { return; }
            if (listSockets.Count == 0) { return; }
            Socket socket = listSockets[0];
            byte[] data = CRC.StringToHexByte(txtHexContent.Text);
            int len = socket.Send(data);
            OutputLine($"已发送{len}个字节:{BitConverter.ToString(data, 0, data.Length)}");
        }

        byte[] closeCommand = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

        private void btnClose_Click(object sender, EventArgs e)
        {
            try
            {
                Socket closeS = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                closeS.Connect(IPAddress.Parse("127.0.0.1"), Port);
                closeS.Send(closeCommand);
                Thread.Sleep(2000);
                int i = 100;
                while (!HasStopped && i > 0)
                {
                    Thread.Sleep(100);
                    i--;
                }
                CloseDeal();
            }
            catch (Exception exc)
            {
                OutputLine(exc.Message);
            }
        }

        private void CloseDeal()
        {
            //foreach (Socket s in listSockets)
            //{
            //    s.Shutdown(SocketShutdown.Both);
            //    s.Close();
            //}
            if (socketReceive != null)
            {
                socketReceive.Shutdown(SocketShutdown.Both);
                socketReceive.Close();
                OutputLine("监听已关闭");
            }
        }

        enum EXTTYPE{Single=0,UseFrameNum=1};

        private DataTable InitCommandList()
        {
            DataTable dt = new DataTable();
            dt.Columns.Add("name");
            dt.Columns.Add("command");
            dt.Columns.Add("ext", typeof(int));
            //
            dt.Rows.Add("查询系统状态", "010101", 0);
            //dt.Rows.Add("单灯打开", "02020101", 0);
            //dt.Rows.Add("单灯关闭", "02020104", 0);
            //dt.Rows.Add("数字表单个拍照", "02020201", 0);
            //dt.Rows.Add("指针表单个拍照", "02020202", 0);
            //dt.Rows.Add("拍照动作是否结束", "010102", 0);
            //dt.Rows.Add("启动图像识别", "02020300", 0);
            //dt.Rows.Add("图像识别是否完成", "010103", 0);
            dt.Rows.Add("查询首帧", "040512-00000001", 0);
            dt.Rows.Add("查询其余帧", "040512-00000002", 1);
            dt.Rows.Add("设置休眠时间", "020204", 2);
            dt.Rows.Add("令终端休眠", "02020600", 0);
            //
            return dt;
        }

        private void cbxCommandList_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cbxCommandList.SelectedIndex > -1)
            {
                DataRowView drv = cbxCommandList.SelectedItem as DataRowView;
                string name = drv["name"].ToString();
                string hexTail = drv["command"].ToString();
                int ext = Convert.ToInt32(drv["ext"]);
                if (ext == 0) //一般命令
                {
                    txtHexContent.Text = GetCommand(txtGatewayId.Text.Trim(), txtL101Code.Text.Trim(), hexTail);
                }
                else if (ext == 1) //图像帧设置
                {
                    hexTail = QueryFrameN((int)nudFrameNums.Value);
                    txtHexContent.Text = GetCommand(txtGatewayId.Text.Trim(), txtL101Code.Text.Trim(), hexTail);
                }
                else if (ext == 2) //休眠时长设置
                {
                    hexTail += Convert.ToString((int)nudFrameNums.Value, 16).PadLeft(2, '0');
                    txtHexContent.Text = GetCommand(txtGatewayId.Text.Trim(), txtL101Code.Text.Trim(), hexTail);
                }
                else
                {
                    txtHexContent.Clear();
                }
                //
                txtCommand.Text = txtHexContent.Text.Replace("-", "").Replace(" ", "");
            }
        }

        internal string QueryFrameN(int n)
        {
            string hex = Convert.ToString(n, 16).PadLeft(8, '0').ToUpper();
            return "040512-" + hex;
        }

        internal string GetCommand(string gatewayid, string nodeid, string hexTail)
        {
            //
            string crc = CRC.crc16_ccitt_xmodem_hostorder(hexTail);
            int len = (hexTail + crc).Replace("-", "").Replace(" ", "").Length / 2;
            string hexLen = Convert.ToString(len, 16).PadLeft(2, '0');
            //
            string hex = gatewayid + "-" + nodeid + "-" + hexLen + "-" + hexTail + "-" + crc;
            //
            return hex;
        }

    }
}